import Board from  '../../components/tile/Board.js'
import Coordinate from  '../../components/tile/Coordinate.js'
import Block from  '../../components/tile/Block.js'
import Utils from './util/utils.js'
import PieceProcess from  '../../components/tile/PieceProcess.js'

export default class Grid {
  constructor(boardSize) {
    this._boardSize = boardSize || 19
    this._a = this._createEmptyMatrix() // 棋子数组
    this._b = this._createEmptyMatrix() // 标记数组
  }

  // 创建空矩阵
  _createEmptyMatrix() {
    return Array(this._boardSize).fill().map(() => 
      Array(this._boardSize).fill(0)
    )
  }

  // 获取棋盘数据
  getChessBoard() {
    return this._a
  }

  // 获取标记数据
  getFlagBoard() {
    return this._b
  }

  // 获取棋子值
  getChessValue(x, y) {
    return this._a[x - 1][y - 1]
  }

  // 设置棋子值
  setChessValue(x, y, value) {
    this._a[x - 1][y - 1] = value
  }

  // 获取标记值
  getFlagValue(x, y) {
    return this._b[x - 1][y - 1]
  }

  // 设置标记值
  setFlagValue(x, y, value) {
    this._b[x - 1][y - 1] = value
  }

  // 清理预落子信息
  clearPreChess() {
    for (let i = 0; i < this._boardSize; i++) {
      for (let j = 0; j < this._boardSize; j++) {
        const num = this._a[i][j]
        if (num === Board.BLACK_PRE || num === Board.WHITE_PRE) {
          this._a[i][j] = Board.NONE
        }
      }
    }
  }

  // 清理棋子信息
  clearChess() {
    this._a = this._createEmptyMatrix()
  }

  // 清理标记信息
  clearFlag() {
    this._b = this._createEmptyMatrix()
  }

  // 获取预落子坐标
  preCoordinate() {
    for (let i = 0; i < this._boardSize; i++) {
      for (let j = 0; j < this._boardSize; j++) {
        const num = this._a[i][j]
        if (num === Board.BLACK_PRE) {
          return new Coordinate(i + 1, j + 1, this._boardSize, Board.BLACK)
        }
        if (num === Board.WHITE_PRE) {
          return new Coordinate(i + 1, j + 1, this._boardSize, Board.WHITE)
        }
      }
    }
    return null
  }

  // 落子
  putPiece(piece) {
    this.setChessValue(piece.c.x, piece.c.y, piece.bw)
    this.startPick(piece.c, piece.bw, piece.removedList)

    // 若落子后会自杀，则返回false
    if (this.isSuicide(piece.c, piece.bw)) {
      this.setChessValue(piece.c.x, piece.c.y, 0) // 还原
      return false
    }

    return true
  }

  // 判断是否自杀
  isSuicide(c, bw) {
    const v = this._createVisitedMatrix()
    const block = new Block(bw)
    this.pick(c, v, bw, block)
    return !block.isLive()
  }

  // 计算气
  airCount(coordinate) {
    const v = this._createVisitedMatrix()
    const bw = coordinate.bw
    const block = new Block(bw)
    this._air(coordinate, v, bw, block)
    return block.airCount
  }

  // 递归计算气
  _air(c, v, bw, block) {
  // 如果是假值，退出函数
    if (!c) return 
    if (v[c.x - 1][c.y - 1]) return

    v[c.x - 1][c.y - 1] = true
    if (this.getChessValue(c.x, c.y) === 0) {
      block.addAir(1)
      return
    } else if (this.getChessValue(c.x, c.y) !== bw) {
      return
    }

    block.add(c)

    for (let i = 0; i < 4; i++) {
      const nc = c.getNear(i)
      this._air(nc, v, bw, block)
    }
  }

  // 开始提子
  startPick(c, bw, removedList) {
    const reBw = new Utils().getReBW(bw)
    this.pickOther(c, reBw, removedList)
  }

  // 提对方子
  pickOther(c, bw, removedList) {
    const v = this._createVisitedMatrix()
    for (let i = 0; i < 4; i++) {
      const nc = c.getNear(i)
      const block = new Block(bw)
      this.pick(nc, v, bw, block)

      if (!block.isLive()) {
        this.deleteBlock(block, removedList)
      }
    }
  }

  // 递归构造块
  pick(c, v, bw, block) {
    if (!c) return
    if (v[c.x - 1][c.y - 1]) return

    if (this.getChessValue(c.x, c.y) === 0) {
      block.addAir(1)
      return
    } else if (this.getChessValue(c.x, c.y) !== bw) {
      return
    }

    v[c.x - 1][c.y - 1] = true
    block.add(c)

    for (let i = 0; i < 4; i++) {
      const nc = c.getNear(i)
      this.pick(nc, v, bw, block)
    }
  }

  // 删除块
  deleteBlock(block, removedList) {
    block.each((coordinate) => {
      this._a[coordinate.x - 1][coordinate.y - 1] = 0
      removedList.push(new PieceProcess(block.bw, coordinate))
    })
  }

  // 创建矩阵
  _createVisitedMatrix() {
    return Array(this._boardSize).fill().map(() => 
      Array(this._boardSize).fill(false)
    )
  }

  // 判断是否相等
  equals(other) {
    if (!other || !other._a) return false
    return this._equalsList(this._a, other._a)
  }

  // 比较两个矩阵
  _equalsList(a, b) {
    for (let j = 0; j < this._boardSize; j++) {
      for (let i = 0; i < this._boardSize; i++) {
        if (a[j][i] !== b[j][i]) return false
      }
    }
    return true
  }

  // 转换为字符串
  toString() {
    let s = ''
    for (let j = 0; j < this._boardSize; j++) {
      for (let i = 0; i < this._boardSize; i++) {
        s += `\t${this._a[j][i]}`
      }
      s += '\n'
    }
    return s
  }
}
